import numpy as np
import pandas as pd
import pickle
import os
from datetime import datetime as datetime_


def save(var, var_name: str):
    f = open(var_name, 'wb')
    pickle.dump(var, f)
    f.close()


def load(var_name: str):
    f = open(var_name, 'rb')
    var = pickle.load(f)
    f.close()
    return var


def cal_y2(price: np.ndarray, T: int, r: int) -> np.ndarray:
    """考虑周期的y标签计算"""
    if T < 0 or r < 0:
        raise ValueError('T < 0, or r < 0')
    if T - r < 1:
        # r(范围)：T-r小于1，导致y的生成包含过去的值
        raise ValueError('T-r<1')
    y_yield = np.array([np.nan]*len(price))
    for i in range(len(price)):
        if i >= len(price) - T - r:
            continue
        y_yield[i] = np.log(price[i + T + r]) - np.log(price[i + T - r])
    return y_yield


def scaler_minmax(data: pd.DataFrame) -> pd.DataFrame:
    """
    Min Max scaler.
    """
    factor_corr_minmax = data.apply(lambda x: (x - np.min(x)) / (np.max(x) - np.min(x)))

    return factor_corr_minmax


def deal_nan(data_df):
    """
    delete rows which contains nan.
    """
    ori_len = len(data_df)
    data_df = data_df.dropna(axis=0, how='any')
    now_len = len(data_df)
    return data_df


def compose(old_dc_ls: list[dict], join_dc_ls: list[dict]) -> list[dict]:
    """将join_dc_ls中的每一个元素匹配到每一个old_dc_ls元素中"""
    if not old_dc_ls:
        return join_dc_ls
    new_dc_ls = []
    for old_dc in old_dc_ls:
        for join_dc in join_dc_ls:
            tem_dc = old_dc.copy()
            tem_dc[list(join_dc.keys())[0]] = join_dc[list(join_dc.keys())[0]]
            new_dc_ls.append(tem_dc)

    return new_dc_ls


def is_file_fixed(last_time, file_path):
    """
    检查文件自上次记录时间以来是否被修改。

    :param last_time: 上次记录的文件修改时间（datetime对象）。
    :param file_path: 要检查的文件路径。
    :return: 如果文件自上次记录以来未修改，返回True；否则返回False。
    """
    # 检查文件是否存在
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"文件 {file_path} 不存在。")

    # 获取文件的最后修改时间
    last_modified_time = datetime_.fromtimestamp(os.path.getmtime(file_path))

    # 对比时间
    return last_modified_time > last_time


def value2px(value, max_min_val_ls, width):
    if max_min_val_ls[0] - max_min_val_ls[1] != 0:
        rate = width / (max_min_val_ls[0] - max_min_val_ls[1])
    else:
        rate = 0
    px = (max_min_val_ls[0] - value) * rate
    return px


def px2value(px, max_min_val_ls, width):
    if '.' in str(max_min_val_ls[0]):
        max_val_decimal_num = len(str(max_min_val_ls[0]).split('.')[1])
    else:
        max_val_decimal_num = 0
    if '.' in str(max_min_val_ls[1]):
        min_val_decimal_num = len(str(max_min_val_ls[1]).split('.')[1])
    else:
        min_val_decimal_num = 0

    decimal_num = max([max_val_decimal_num, min_val_decimal_num])
    if decimal_num > 3:
        decimal_num = 3
    rate = (max_min_val_ls[0] - max_min_val_ls[1]) / width
    value = round(max_min_val_ls[0] - (px - 0) * rate, decimal_num)
    return value


def round_rectangle(x1, y1, x2, y2, radius=3):
    if y1 == y2:
        points = [x1, y1+1,
                  x2, y2+1,
                  x2, y2,
                  x1, y1]
    else:
        points = [x1 + radius, y1,
                  x1 + radius, y1,
                  x2 - radius, y1,
                  x2 - radius, y1,
                  x2, y1,
                  x2, y1 + radius,
                  x2, y1 + radius,
                  x2, y2 - radius,
                  x2, y2 - radius,
                  x2, y2,
                  x2 - radius, y2,
                  x2 - radius, y2,
                  x1 + radius, y2,
                  x1 + radius, y2,
                  x1, y2,
                  x1, y2 - radius,
                  x1, y2 - radius,
                  x1, y1 + radius,
                  x1, y1 + radius,
                  x1, y1]

    return points


